/**
 * 
 */
package cz.cvut.fit.crhonjar.mi.paa.dunedin;

import cz.cvut.fit.crhonjar.mi.paa.dunedin.exception.DunedinException;

/**
 * @author Jarec
 * 
 */
public class Bucket implements Cloneable {

	private int actual;
	private final int capacity;
	private final int finalVolume;

	public Bucket(final int capacity, final int actual, final int finalVolume) {
		if (capacity < actual) {
			throw new IllegalArgumentException(
					"Capacity cannot be higher than actual water state!");
		}
		if (finalVolume > capacity) {
			throw new IllegalArgumentException(
					"Capacity cannot be higher than desired final volume!");
		}

		this.capacity = capacity;
		this.actual = actual;
		this.finalVolume = finalVolume;
	}

	public void accept(final int water) throws DunedinException {
		if ((this.actual + water) > this.capacity) {
			throw new DunedinException(
					"Bucket cannot accept water, than is actual free capacity.");
		} else {
			this.actual += water;
		}
	}

	@Override
	public Bucket clone() {
		return new Bucket(this.capacity, this.actual, this.finalVolume);
	}

	public void dump() {
		this.actual = 0;
	}

	public void fill() {
		this.actual = this.capacity;
	}

	/**
	 * @return the actual
	 */
	public int getActual() {
		return this.actual;
	}

	/**
	 * @return the capacity
	 */
	public int getCapacity() {
		return this.capacity;
	}

	/**
	 * @return the finalVolume
	 */
	public int getFinalVolume() {
		return this.finalVolume;
	}

	public int getFreeSpace() {
		return this.capacity - this.actual;
	}

	public boolean isEmpty() {
		return this.actual == 0;
	}

	public boolean isFinalVolumeReached() {
		return this.finalVolume == this.actual;
	}

	public boolean isFull() {
		return this.getFreeSpace() == 0;
	}

	public void pourTo(final Bucket b) throws DunedinException {
		if (b == null) {
			throw new IllegalArgumentException("Cannot pour to NULL bucket!");
		}
		if (b.isFull()) {
			throw new DunedinException("Cannot pour to full bucket!");
		}
		if (this == b) {
			throw new IllegalArgumentException("Cannot pour to same bucket!");
		}
		if (this.getActual() >= b.getFreeSpace()) {
			this.actual -= b.getFreeSpace();
			b.fill();
		} else {
			b.accept(this.actual);
			this.actual = 0;
		}
	}

}
